home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / progut~1 / stdwin.zoo / alfa / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-10-18  |  9.0 KB  |  561 lines

  1. /* TERMCAP STDWIN -- MENUS. */
  2.  
  3. #include "alfa.h"
  4.  
  5. static bool deflocal= FALSE;    /* Default menu state */
  6.  
  7. static struct menubar gmenus;    /* All global menus */
  8. static struct menubar lmenus;    /* All local menus */
  9.  
  10. static MENU *sysmenu;        /* Window selection commands */
  11.  
  12. static void
  13. addtobar(mbp, mp)
  14.     struct menubar *mbp;
  15.     MENU *mp;
  16. {
  17.     int i;
  18.     
  19.     for (i= 0; i < mbp->nmenus; ++i) {
  20.         if (mp == mbp->menulist[i])
  21.             return; /* Already attached */
  22.     }
  23.     L_APPEND(mbp->nmenus, mbp->menulist, MENU *, mp);
  24. }
  25.  
  26. static void
  27. delfrombar(mbp, mp)
  28.     struct menubar *mbp;
  29.     MENU *mp;
  30. {
  31.     int i;
  32.     
  33.     for (i= 0; i < mbp->nmenus; ++i) {
  34.         if (mp == mbp->menulist[i]) {
  35.             L_REMOVE(mbp->nmenus, mbp->menulist,
  36.                 MENU *, i);
  37.             break;
  38.         }
  39.     }
  40. }
  41.  
  42. _winitmenus()
  43. {
  44.     sysmenu= wmenucreate(0, "STDWIN");
  45.     wmenuadditem(sysmenu, "Previous Window", -1);
  46.     wmenuadditem(sysmenu, "Next Window", -1);
  47.     wmenuadditem(sysmenu, "Close Window", -1);
  48.     wmenuadditem(sysmenu, "(left)", -1);
  49.     wmenuadditem(sysmenu, "(right)", -1);
  50.     wmenuadditem(sysmenu, "(up)", -1);
  51.     wmenuadditem(sysmenu, "(down)", -1);
  52.     wmenuadditem(sysmenu, "(cancel)", -1);
  53.     wmenuadditem(sysmenu, "(backspace)", -1);
  54.     wmenuadditem(sysmenu, "(tab)", -1);
  55.     wmenuadditem(sysmenu, "(return)", -1);
  56.     /* Shortcuts are compiled in the key map! */
  57. }
  58.  
  59. MENU *
  60. wmenucreate(id, title)
  61.     int id;
  62.     char *title;
  63. {
  64.     MENU *mp= ALLOC(MENU);
  65.     
  66.     if (mp == NULL)
  67.         return NULL;
  68.     mp->id= id;
  69.     mp->title= strdup(title);
  70.     mp->local= deflocal;
  71.     mp->dirty= TRUE;
  72.     mp->left= mp->right= 0;
  73.     L_INIT(mp->nitems, mp->itemlist);
  74.     addtobar(mp->local ? &lmenus : &gmenus, mp);
  75.     if (!mp->local)
  76.         menubarchanged();
  77.     return mp;
  78. }
  79.  
  80. void
  81. wmenudelete(mp)
  82.     MENU *mp;
  83. {
  84.     int i;
  85.     
  86.     if (mp->local) {
  87.         for (i= 0; i < MAXWINDOWS; ++i) {
  88.             if (winlist[i].open)
  89.                 delfrombar(&winlist[i].mbar, mp);
  90.         }
  91.     }
  92.     delfrombar(mp->local ? &lmenus : &gmenus, mp);
  93.     for (i= 0; i < mp->nitems; ++i) {
  94.         FREE(mp->itemlist[i].text);
  95.         FREE(mp->itemlist[i].shortcut);
  96.     }
  97.     L_DEALLOC(mp->nitems, mp->itemlist);
  98.     FREE(mp);
  99.     menubarchanged();
  100. }
  101.  
  102. int
  103. wmenuadditem(mp, text, shortcut)
  104.     MENU *mp;
  105.     char *text;
  106.     int shortcut;
  107. {
  108.     struct item it;
  109.     
  110.     mp->dirty= TRUE;
  111.     it.text= strdup(text);
  112.     it.shortcut= NULL;
  113.     it.enabled= (text != NULL && *text != EOS);
  114.     it.checked= FALSE;
  115.     L_APPEND(mp->nitems, mp->itemlist, struct item, it);
  116.     if (shortcut >= 0)
  117.         wsetmetakey(mp->id, mp->nitems-1, shortcut);
  118.     return mp->nitems-1;
  119. }
  120.  
  121. void
  122. wmenusetitem(mp, item, text)
  123.     MENU *mp;
  124.     int item;
  125.     char *text;
  126. {
  127.     if (item < 0 || item >= mp->nitems)
  128.         return;
  129.     mp->dirty= TRUE;
  130.     FREE(mp->itemlist[item].text);
  131.     mp->itemlist[item].text= strdup(text);
  132.     mp->itemlist[item].enabled= (text != NULL && *text != EOS);
  133. }
  134.  
  135. void
  136. wmenuenable(mp, item, flag)
  137.     MENU *mp;
  138.     int item;
  139.     int flag;
  140. {
  141.     if (item < 0 || item >= mp->nitems)
  142.         return;
  143.     mp->itemlist[item].enabled= flag;
  144. }
  145.  
  146. void
  147. wmenucheck(mp, item, flag)
  148.     MENU *mp;
  149.     int item;
  150.     int flag;
  151. {
  152.     if (item < 0 || item >= mp->nitems)
  153.         return;
  154.     mp->itemlist[item].checked= flag;
  155. }
  156.  
  157. void
  158. wmenuattach(win, mp)
  159.     WINDOW *win;
  160.     MENU *mp;
  161. {
  162.     if (!mp->local)
  163.         return;
  164.     addtobar(&win->mbar, mp);
  165.     if (win == front)
  166.         menubarchanged();
  167. }
  168.  
  169. void
  170. wmenudetach(win, mp)
  171.     WINDOW *win;
  172.     MENU *mp;
  173. {
  174.     if (!mp->local)
  175.         return;
  176.     delfrombar(&win->mbar, mp);
  177.     if (win == front)
  178.         menubarchanged();
  179. }
  180.  
  181. void
  182. wmenusetdeflocal(local)
  183.     bool local;
  184. {
  185.     deflocal= local;
  186. }
  187.  
  188. /* Interface routines for the rest of the library. */
  189.  
  190. void
  191. initmenubar(mb)
  192.     struct menubar *mb;
  193. {
  194.     L_INIT(mb->nmenus, mb->menulist);
  195. }
  196.  
  197. void
  198. killmenubar(mb)
  199.     struct menubar *mb;
  200. {
  201.     L_DEALLOC(mb->nmenus, mb->menulist);
  202. }
  203.  
  204. void
  205. drawmenubar() /* This is part of the syswin draw procedure! */
  206. {
  207.     WINDOW *win= front;
  208.     char buf[256];
  209.     int k= 0;
  210.     int i;
  211.     
  212.     buf[0]= EOS;
  213.     for (i= 0; i < gmenus.nmenus; ++i)
  214.         k= bufappend(buf, k, gmenus.menulist[i]);
  215.     if (win != NULL) {
  216.         for (i= 0; i < win->mbar.nmenus; ++i)
  217.             k= bufappend(buf, k, win->mbar.menulist[i]);
  218.     }
  219.     wdrawtext(0, 0, buf, -1);
  220. }
  221.  
  222. static int
  223. bufappend(buf, pos, mp)
  224.     char *buf;
  225.     int pos;
  226.     MENU *mp;
  227. {
  228.     if (pos > 0) {
  229.         buf[pos++]= ' ';
  230.         buf[pos++]= ' ';
  231.     }
  232.     mp->left= pos;
  233.     strcpy(buf+pos, mp->title);
  234.     pos += (int)strlen(buf+pos);
  235.     mp->right= pos;
  236.     return pos;
  237. }
  238.  
  239. /* TO DO:
  240.    - highlight current menu title, current menu item
  241.    - remember last menu and item
  242.    - Allow GOTO to select menus or menu items
  243.      (m-down on mbar opens the menu; m-up on item selects the item)
  244. */
  245.  
  246. static void menudraw(), menuitemdraw(), menucalcwidth();
  247. static bool handleevt(), handlecmd(), handlemenu();
  248. static int calcleft();
  249.  
  250. static leftblank;
  251.  
  252. static bool        curlocal;
  253. static struct menubar *    curmbar;
  254. static int        curimenu;
  255. static MENU *        curmenu;
  256. static int        curitem;
  257. static int        lowest;
  258.  
  259. static bool
  260. firstmenu()
  261. {
  262.     curlocal= FALSE;
  263.     curmbar= &gmenus;
  264.     curimenu= 0;
  265.     
  266.     if (curmbar->nmenus == 0) {
  267.         curmbar= &lmenus;
  268.         curlocal= TRUE;
  269.         if (curmbar->nmenus == 0) {
  270.             wmessage("No menus defined");
  271.             return FALSE;
  272.         }
  273.     }
  274.     curmenu= curmbar->menulist[curimenu];
  275.     curitem= 0;
  276.     menudraw();
  277.     return TRUE;
  278. }
  279.  
  280. static void
  281. nextmenu()
  282. {
  283.     ++curimenu;
  284.     while (curimenu >= curmbar->nmenus) {
  285.         curlocal= !curlocal;
  286.         curmbar= curlocal ? &lmenus : &gmenus;
  287.         curimenu= 0;
  288.     }
  289.     curmenu= curmbar->menulist[curimenu];
  290.     curitem= 0;
  291.     menudraw();
  292. }
  293.  
  294. static void
  295. prevmenu()
  296. {
  297.     --curimenu;
  298.     while (curimenu < 0) {
  299.         curlocal= !curlocal;
  300.         curmbar= curlocal ? &lmenus : &gmenus;
  301.         curimenu= curmbar->nmenus - 1;
  302.     }
  303.     curmenu= curmbar->menulist[curimenu];
  304.     curitem= 0;
  305.     menudraw();
  306. }
  307.  
  308. static void
  309. nextitem()
  310. {
  311.     ++curitem;
  312.     if (curitem >= curmenu->nitems)
  313.         curitem= 0;
  314.     trmsync(curitem+1, curmenu->left);
  315. }
  316.  
  317. static void
  318. previtem()
  319. {
  320.     --curitem;
  321.     if (curitem < 0)
  322.         curitem= curmenu->nitems - 1;
  323.     trmsync(curitem+1, curmenu->left);
  324. }
  325.  
  326. static void
  327. selectitem(ep)
  328.     EVENT *ep;
  329. {
  330.     char *text;
  331.     
  332.     ep->type= WE_NULL;
  333.     if (curitem >= curmenu->nitems || !curmenu->itemlist[curitem].enabled)
  334.         return;
  335.     ep->type= WE_MENU;
  336.     ep->u.m.id= curmenu->id;
  337.     ep->u.m.item= curitem;
  338. }
  339.  
  340. void
  341. menuselect(ep)
  342.     EVENT *ep;
  343. {
  344.     leftblank= columns;
  345.     lowest= 0;
  346.     wmessage((char *)NULL);
  347.     if (!firstmenu())
  348.         return;
  349.     for (;;) {
  350.         wsysevent(ep, TRUE);
  351.         if (handleevt(ep))
  352.             break;
  353.     }
  354. }
  355.  
  356. static bool
  357. handleevt(ep)
  358.     EVENT *ep;
  359. {
  360.     switch (ep->type) {
  361.     
  362.     case WE_MENU:
  363.         return handlemenu(ep);
  364.     
  365.     case WE_COMMAND:
  366.         return handlecmd(ep);
  367.     
  368.     default:
  369.         trmbell();
  370.         return FALSE;
  371.     
  372.     }
  373. }
  374.  
  375. static bool
  376. handlecmd(ep)
  377.     EVENT *ep;
  378. {
  379.     switch (ep->u.command) {
  380.     
  381.     default:
  382.         trmbell();
  383.         return FALSE;
  384.     
  385.     case WC_RETURN:
  386.         selectitem(ep);
  387.         if (curmenu == sysmenu)
  388.             wsyscommand(ep);
  389.         return TRUE;
  390.     
  391.     case WC_LEFT:
  392.         prevmenu();
  393.         break;
  394.     
  395.     case WC_RIGHT:
  396.         nextmenu();
  397.         break;
  398.     
  399.     case WC_UP:
  400.         previtem();
  401.         break;
  402.     
  403.     case WC_DOWN:
  404.         nextitem();
  405.         break;
  406.     
  407.     case WC_CANCEL:
  408.         ep->type= WE_NULL;
  409.         return TRUE;
  410.     
  411.     }
  412.     return FALSE;
  413. }
  414.  
  415. static bool
  416. handlemenu(ep)
  417.     EVENT *ep;
  418. {
  419.     if (ep->u.m.id != 0)
  420.         return TRUE;
  421.     switch (ep->u.m.item) {
  422.     
  423.     case SUSPEND_PROC:
  424.         _wsuspend();
  425.         menudraw();
  426.         break;
  427.     
  428.     case REDRAW_SCREEN:
  429.         _wredraw();
  430.         menudraw();
  431.         break;
  432.     
  433.     case MENU_CALL:
  434.         ep->type= WE_NULL;
  435.         return TRUE;
  436.  
  437.     default:
  438.         if (ep->u.m.item <= LAST_CMD) {
  439.             wsyscommand(ep);
  440.             if (ep->type == WE_COMMAND)
  441.                 return handlecmd(ep);
  442.             else
  443.                 return TRUE;
  444.         }
  445.         else {
  446.             trmbell();
  447.             return FALSE;
  448.         }
  449.     
  450.     }
  451.     return FALSE;
  452. }
  453.  
  454. static void
  455. menudraw()
  456. {
  457.     MENU *mp= curmenu;
  458.     int left;
  459.     int width;
  460.     int i;
  461.     
  462.     wupdate(syswin);
  463.     if (mp->dirty)
  464.         menucalcwidth(mp);
  465.     left= calcleft(mp);
  466.     width= mp->maxwidth;
  467.     if (left + width > columns)
  468.         width= columns - left;
  469.     for (i= 0; i < mp->nitems; ++i)
  470.         menuitemdraw(i+1, left, &mp->itemlist[i], width);
  471.     if (i+1 > lowest)
  472.         lowest= i+1;
  473.     else if (i+1 < lowest)
  474.         trmputdata(i+1, lowest-1, 0, "");
  475.     leftblank= left;
  476.     trmsync(curitem+1, mp->left);
  477. }
  478.  
  479. static int
  480. calcleft(mp)
  481.     MENU *mp;
  482. {
  483.     int left= columns - mp->maxwidth;
  484.     
  485.     if (left > mp->left)
  486.         left= mp->left;
  487.     if (left < 0)
  488.         left= 0;
  489.     if (left-3 < leftblank) {
  490.         leftblank= left-3;
  491.         if (leftblank < 4)
  492.             leftblank= 0;
  493.     }
  494.     return left;
  495. }
  496.  
  497. static void
  498. menuitemdraw(line, left, ip, width)
  499.     int line, left;
  500.     struct item *ip;
  501.     int width;
  502. {
  503.     char buf[256];
  504.     int margin= left-leftblank;
  505.     
  506.     buf[0]= EOS;
  507.     if (ip->text != NULL && *ip->text != EOS) {
  508.         int space;
  509.         char *p= buf;
  510.         for (space= margin; space-- > 0; )
  511.             *p++ = ' ';
  512.         if (ip->checked && margin >= 2)
  513.             p[-2]= '*';
  514.         strcpy(p, ip->text);
  515.         p += strlen(p);
  516.         if (!ip->enabled && margin >= 1 &&
  517.             ip->text != NULL && ip->text[0] != EOS) {
  518.             buf[margin-1]= '(';
  519.             *p++= ')';
  520.         }
  521.         if (ip->shortcut != NULL && *ip->shortcut != EOS) {
  522.             space= width - (p - buf - margin)
  523.                 - (int)strlen(ip->shortcut);
  524.             if (space <= 0)
  525.                 space= 2;
  526.             while (--space >= 0)
  527.                 *p++ = ' ';
  528.             strcpy(p, ip->shortcut);
  529.         }
  530.     }
  531.     trmputdata(line, line, leftblank, buf);
  532.     uptodate[line]= FALSE;
  533. }
  534.  
  535. static void
  536. menucalcwidth(mp)
  537.     MENU *mp;
  538. {
  539.     int i;
  540.     int width= 0;
  541.     
  542.     for (i= 0; i < mp->nitems; ++i) {
  543.         struct item *ip= &mp->itemlist[i];
  544.         char *text= ip->text;
  545.         if (text != NULL && *text != EOS) {
  546.             int w= (int)strlen(text);
  547.             if (ip->shortcut == NULL) {
  548.                 char buf[256];
  549.                 getbindings(buf, mp->id, i);
  550.                 ip->shortcut= strdup(buf);
  551.             }
  552.             if (ip->shortcut != NULL && *ip->shortcut != EOS)
  553.                 w += 2 + (int)strlen(ip->shortcut);
  554.             if (w > width)
  555.                 width= w;
  556.         }
  557.     }
  558.     mp->maxwidth= width;
  559.     mp->dirty= FALSE;
  560. }
  561.